﻿#include "ccameraconnectbasler.h"
#include<QDebug>
#include <pylon/gige/BaslerGigEInstantCamera.h>

CcameraConnectBasler::CcameraConnectBasler(QString cameraName)
{
    Pylon::PylonInitialize();
    m_cameraName = cameraName;
    Pylon::CTlFactory& tlFactory = Pylon::CTlFactory::GetInstance();
    int devicesNum = tlFactory.EnumerateDevices(m_devList);

    for (int i = 0; i < devicesNum; i++)
    {
        QString deviceName = m_devList[i].GetUserDefinedName();
        if(cameraName == deviceName)
        {
            m_camera = new Camera_t(Pylon::CTlFactory::GetInstance().CreateDevice(m_devList[i]));
            m_camera->GrabCameraEvents = true;
            break;
        }
    }
    qDebug()<<"find camera__"<<m_nameList;

}

CcameraConnectBasler::~CcameraConnectBasler()
{
    if(!m_camera) return;
    m_camera->DestroyDevice();
}

bool CcameraConnectBasler::findCamera()
{
    //创建相机对象（以最先识别的相机）
    if(!m_camera) return false;
    //    qDebug() << "Using device " << m_camera->GetDeviceInfo().GetModelName();
    //    qDebug() << "Using device " << m_camera->GetDeviceInfo().GetUserDefinedName();
    if(m_camera->GetDeviceInfo().GetUserDefinedName() == m_cameraName)//根据相机名寻找相机
    {
        qDebug()<<QStringLiteral("找到相机，可以连接！");
        return true;
    }
    qDebug()<<QStringLiteral("未找到相机！");
    return false;
}

bool CcameraConnectBasler::connect()
{
    if(!m_camera->IsOpen())
    {
        if(findCamera())
        {
            m_camera->Open();    //连接名称为cameraName的相机
            m_nodeMap = &m_camera->GetNodeMap();
            GetIntPara("Width", width);
            GetIntPara("Height", height);
            width = width  - (width%4);
            height = height - (height%4);
            SetIntPara("Width", width);
            SetIntPara("Height", height);
            if(!m_camera->IsOpen())
            {
                qDebug()<<QStringLiteral("找到相机，连接失败！");
                return false;
            }
            qDebug()<<QStringLiteral("连接相机成功！");
            return true;
        }
        qDebug()<<QStringLiteral("未找到相机，连接失败！");
        return false;
    }
    qDebug()<<QStringLiteral("相机已经连接！");
    return true;
}

bool CcameraConnectBasler::disConnect()
{
    if(isConnected())
    {
        m_camera->Close();
        qDebug()<<QStringLiteral("相机断开连接成功！");
        return true;
    }
    else
        qDebug()<<QStringLiteral("相机断开连接失败！");
    return true;
}

bool CcameraConnectBasler::isConnected()
{
    if(!m_camera->IsOpen())
        return false;
    else
        return true;
}

bool CcameraConnectBasler::setSoftTrigger()
{
    //    INodeMap& nodemap = m_camera->GetNodeMap();
    CEnumerationPtr  ptrTriggerSource = m_nodeMap->GetNode ("TriggerSource");
    ptrTriggerSource->FromString("Software");

    //    camera.ExecuteSoftwareTrigger();
    return true;
}

bool CcameraConnectBasler::setExposureTime(double exposureTime)
{
    if (!m_camera->IsOpen())return false;
    try
    {
        //        INodeMap& nodemap = m_camera->GetNodeMap();
        CFloatPtr m_exposureTime = m_nodeMap->GetNode("ExposureTimeAbs");
        m_exposureTime->SetValue(exposureTime);//待转换
        return true;
    }
    catch (GenICam::GenericException& e)
    {
        qDebug() << e.GetDescription();
        return false;
    }
}

bool CcameraConnectBasler::setGainRaw(double gain)
{
    if (!m_camera->IsOpen())return false;
    try
    {
        //        INodeMap& nodemap = m_camera->GetNodeMap();
        CIntegerPtr GainRaw = m_nodeMap->GetNode("GainRaw");
        GainRaw->SetValue(gain);
        return true;
    }
    catch (GenICam::GenericException& e)
    {
        qDebug() << e.GetDescription();
        return false;
    }
}

bool CcameraConnectBasler::getExposureTime(double *expTime)
{
    if (!m_camera->IsOpen())return false;
    try
    {
        CFloatPtr m_exposureTime = m_nodeMap->GetNode("ExposureTimeAbs");
        *expTime =  m_exposureTime->GetValue();
        return true;
    }
    catch (GenICam::GenericException& e)
    {
        qDebug() << e.GetDescription();
        return false;
    }
}

bool CcameraConnectBasler::getGainRaw(double *gain)
{
    if (!m_camera->IsOpen())return false;
    try
    {
        //        INodeMap& nodemap = m_camera->GetNodeMap();
        CIntegerPtr GainRaw = m_nodeMap->GetNode("GainRaw");
        *gain = GainRaw->GetValue();
        return true;
    }
    catch (GenICam::GenericException& e)
    {
        qDebug() << e.GetDescription();
        return false;
    }
}

bool CcameraConnectBasler::getOneFrame(Hobject* himage)
{
    int i=0;
    //如果在十次以内获取到帧图像
    CGrabResultPtr ptrGrabResult;
    while (m_camera->IsGrabbing()&& i<10)
    {
        // 等待接收和恢复图像，超时时间设置为5000 ms.
        m_camera->RetrieveResult(500, ptrGrabResult, TimeoutHandling_ThrowException);
        i++;
        // 判断是否抓图成功
        if (!ptrGrabResult->GrabSucceeded())
        {
            continue;
        }
        break;
    }

    //图像格式转换
    if(ptrGrabResult->GetPixelType() == PixelType_Mono8)
    {
        CPylonImage pylonImage;
        CImageFormatConverter formatConverter;
        formatConverter.OutputPixelFormat = PixelType_Mono8;
        formatConverter.Convert(pylonImage, ptrGrabResult);
        int m_width = ptrGrabResult->GetWidth();
        int m_height = ptrGrabResult->GetHeight();
        if (m_buffer.size() != m_width * m_height)
            m_buffer.resize(m_width * m_height);
        memcpy(m_buffer.data(), ptrGrabResult->GetBuffer(), m_width * m_height);
        //相机停止抓图
        QImage image = QImage(m_buffer.data(), m_width, m_height, QImage::Format_Grayscale8);
        *himage = QImageToHobject(&image,1);
    }
    else
    {
        CPylonImage targetImage;
        CImageFormatConverter converter;
        converter.OutputPixelFormat = PixelType_RGB8packed;
        converter.Convert(targetImage, ptrGrabResult);
        int width = targetImage.GetWidth();
        int height = targetImage.GetHeight();
        void *buf = targetImage.GetBuffer();
        width = width  - (width%4);
        height = height - (height%4);
        uchar *pp = new uchar[width*height*3];
        QImage *imgColor = new QImage(pp,width,height,QImage::Format_RGB888);
//        QImage image =QImage(pp,width,height,QImage::Format_RGB888);
        memcpy(pp, buf, width * height  * 3);
        *himage = QImageToHobject(imgColor,2);
        delete pp;
        delete imgColor;
    }
    return true;
}

bool CcameraConnectBasler::grabOneFrame(Hobject *himage)
{
    if(openGrabFrame())
    {
        if(getOneFrame(himage))
        {
            if(stopGrabFrame())
                return true;
        }
        return false;
    }
    return false;
}

bool CcameraConnectBasler::openGrabFrame()
{
    if(!isConnected())
    {
        qDebug()<<QStringLiteral("连接失败，先连接相机再采图！");
        return false;
    }
    qDebug()<<QStringLiteral("开始采图！");
    //相机开始抓图
    m_camera->StartGrabbing();
    return true;
}

bool CcameraConnectBasler::stopGrabFrame()
{
    if(!isConnected())
    {
        qDebug()<<QStringLiteral("连接失败，先连接相机再采图！");
        return false;
    }
    m_camera->StopGrabbing();
    return true;
}

Hobject CcameraConnectBasler::QImageToHobject(QImage *image,int Type)
{
    if(Type ==1) //黑白图像格式转换
    {
        unsigned char *data = (*image).bits();//获取图像像素字节数据的首地址
        int width = (*image).width();//图像宽
        int height = (*image).height();//图像高
        unsigned char* hdata=(unsigned char*)malloc(width*height);//存储处理后的数据
        for (int i=0;i<height;i++)
        {
            for (int j=0;j<width;j++)
            {
                hdata[i*width+j]  =*data;
                data+=1;
            }
        }
        Hobject himg;
        gen_image1(&himg, "byte", width, height, (Hlong)(hdata));
        free(hdata);
        return himg;
    }
    else //彩色图像
    {
        unsigned char *data=(*image).bits();//获取图像像素字节数据的首地址
        int width=(*image).width();//图像宽
        int height=(*image).height();//图像高

        unsigned char* dataRed=(unsigned char*)malloc(width*height);//存储处理后的数据
        unsigned char* dataGreen=(unsigned char*)malloc(width*height);//存储处理后的数据
        unsigned char* dataBlue=(unsigned char*)malloc(width*height);//存储处理后的数据
        for (int i=0;i<height;i++)
        {
            for (int j=0;j<width;j++)
            {
                dataRed[i*width+j]  =*(data);
                dataGreen[i*width+j]=*(data+1);
                dataBlue[i*width+j]=*(data+2);
                data+=3;
            }
        }
        Hobject himg;
        gen_image3(&himg, "byte", width, height, (Hlong)(dataRed), (Hlong)(dataGreen), (Hlong)(dataBlue));
        free(dataBlue);
        free(dataGreen);
        free(dataRed);
        return himg;

    }
}
bool CcameraConnectBasler::GetIntPara(const char *nameNode, int64_t &para)
{
    if( m_nodeMap ) {
        CIntegerPtr tmp( m_nodeMap->GetNode( nameNode));
        para = tmp->GetValue();
        return true;
    }
    return false;
}

bool CcameraConnectBasler::SetIntPara(const char *nameNode, INT64 para)
{
    if( m_nodeMap ) {
        CIntegerPtr tmp( m_nodeMap->GetNode( nameNode ));
        if ( IsWritable(tmp) ) {
            para = Adjust(para, tmp->GetMin(), tmp->GetMax(), tmp->GetInc());
            tmp->SetValue(para);
            return true;
        }
        else
            return false;
    }
    return false;
}

int64_t CcameraConnectBasler::Adjust(int64_t val, int64_t minimum, int64_t maximum, int64_t inc)
{
    /* Check the input parameters. */
    if (inc <= 0) {
        /*Negative increments are invalid.*/
        throw LOGICAL_ERROR_EXCEPTION("Unexpected increment %d", inc);
    }

    if (minimum > maximum) {
        /* Minimum must not be bigger than or equal to the maximum.*/
        throw LOGICAL_ERROR_EXCEPTION("minimum bigger than maximum.");
    }

    /*Check the lower bound.*/
    if (val < minimum) {
        return minimum;
    }

    /*Check the upper bound.*/
    if (val > maximum) {
        return maximum;
    }

    /*Check the increment.*/
    if (inc == 1) {
        /*Special case: all values are valid.*/
        return val;
    } else {
        /*The value must be min + (n * inc).*/
        /*Due to the integer division, the value will be rounded down.*/
        return minimum + ( ((val - minimum) / inc) * inc );
    }
}
